package org.hit.burkun.network.models;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.Map.Entry;

import org.hit.burkun.network.EdgeInfo;
import org.hit.burkun.network.SerializableGraph;
import org.hit.burkun.network.Vertex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RandomWalkWithRestart extends SimplePageRank {
	private Vertex reVertex;
	private static Logger log = LoggerFactory.getLogger(RandomWalkWithRestart.class);

	public RandomWalkWithRestart(SerializableGraph graph, Vertex restartVertex) {
		super(graph);
		this.reVertex = restartVertex;
	}

	@Override
	protected ArrayList<Double> doRank() {
		Collection<Vertex> vs = graph.getAllVertexs();
		ArrayList<Double> newPr = new ArrayList<Double>(graph.getAllVertexs()
				.size());
		initPrVector(newPr);
		for (Vertex v : vs) {
			// get all edges,求内积
			LinkedList<EdgeInfo> edgeInfos = matrix.get(v);
			double sums = 0;
			if (edgeInfos != null) {
				for (EdgeInfo ei : edgeInfos) {
					double tempPR = pr.get(ei.getVertex().getUid());
					sums += tempPR * ei.getScore();
				}
				//already mutiply zuni
			} else {
				// 只有出链没有入链
			}
			newPr.set(v.getUid(), sums);
		}
		return newPr;
	}
	
	@Override
	protected void initMatrix(boolean useWeight) {
		log.debug("init matrix with weight...");
		HashMap<Vertex, LinkedList<EdgeInfo>> edges = graph.getEdgeMap();
		Set<Entry<Vertex, LinkedList<EdgeInfo>>> entries = edges.entrySet();
		SerializableGraph newSg = new SerializableGraph();
		for (Entry<Vertex, LinkedList<EdgeInfo>> entry : entries) {
			Vertex v = entry.getKey();
			LinkedList<EdgeInfo> edge = entry.getValue();
			if (edge.size() != 0) {
				double sizeSum = edge.size();
				if (useWeight) {
					sizeSum = 0;
					for (EdgeInfo ei : edge) {
						sizeSum += ei.getScore();
					}
				}
				for (EdgeInfo ei : edge) {
					// reverse edges
					EdgeInfo eei = null;
					if(useWeight){
						//使用自带的权值更新
						eei = new EdgeInfo(v, ei.getRelType());
						if(sizeSum > 0){
							eei.setScore((1-zuNi) * ei.getScore() / sizeSum);
						}else{
							eei.setScore(0);
						}
					
					}else{
						//不使用权值，当使用权值的时候，会出现所有权值消失的怪事儿
						eei = new EdgeInfo(v, ei.getRelType());
						if(sizeSum > 0){
							eei.setScore((1-zuNi) / sizeSum);						
						}else{
							eei.setScore(0);
						}
					}
					newSg.addEdge(ei.getVertex(), eei);
				}
			}
		}
		matrix = newSg.getEdgeMap();
		LinkedList<EdgeInfo> edgeInfo = matrix.get(graph.getVertexByUmls(reVertex.getUmlsId()));
		HashSet<Vertex> marked = new HashSet<>();
		if(edgeInfo != null){
			for(EdgeInfo e : edgeInfo){
				marked.add(e.getVertex());
				e.setScore(e.getScore() + zuNi);
			}
		}else{
			LinkedList<EdgeInfo> newEdgeInfo = new LinkedList<EdgeInfo>();
			matrix.put(graph.getVertexByUmls(reVertex.getUmlsId()), newEdgeInfo);
			edgeInfo = newEdgeInfo;
		}
		Collection<Vertex> allV = graph.getAllVertexs();
		for(Vertex v : allV){
			//add all links
			if(!marked.contains(v)){
				//使用空的阻尼
				EdgeInfo e = new EdgeInfo(v, "nothing");
				e.setScore(zuNi);
				edgeInfo.add(e);
			}
		}
		matrix.put(graph.getVertexByUmls(reVertex.getUmlsId()), edgeInfo);
//		checkAllOne();
	}
	
	private void checkAllOne(){
		Set<Vertex> vs  = matrix.keySet();
		double[] sums = new double[vs.size()];
		for(Vertex v : vs){
			LinkedList<EdgeInfo> edg = matrix.get(v);
			for(EdgeInfo e : edg){
				sums[e.getVertex().getUid()] += e.getScore();
			}
		}
		for(int i=0; i<vs.size(); i++){
			if(sums[i]!=1){
				System.out.println(sums[i]);
			}
		}
	}
	

}
